home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C101.ZIP / UUPC11XS.ZIP / UUCICO / ULIBOS2.C < prev    next >
C/C++ Source or Header  |  1992-12-11  |  35KB  |  955 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    u l i b o s 2 . c                                               */
  3. /*                                                                    */
  4. /*    OS/2 serial port support for UUCICO                             */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989 by Andrew H. Derbyshire.             */
  9. /*                                                                    */
  10. /*    Changes Copyright (c) 1990-1992 by Kendra Electronic            */
  11. /*    Wonderworks.                                                    */
  12. /*                                                                    */
  13. /*    All rights reserved except those explicitly granted by the      */
  14. /*    UUPC/extended license agreement.                                */
  15. /*--------------------------------------------------------------------*/
  16.  
  17. /*--------------------------------------------------------------------*/
  18. /*                          RCS Information                           */
  19. /*--------------------------------------------------------------------*/
  20.  
  21. /*
  22.  *       $Id: ulibos2.c 1.6 1992/12/11 12:45:11 ahd Exp $
  23.  *       $Log: ulibos2.c $
  24.  * Revision 1.6  1992/12/11  12:45:11  ahd
  25.  * Correct RTS handshake
  26.  *
  27.  * Revision 1.5  1992/12/04  01:00:27  ahd
  28.  * Add copyright message, reblock other comments
  29.  *
  30.  * Revision 1.4  1992/11/29  22:09:10  ahd
  31.  * Add new define for BC++ OS/2 build
  32.  *
  33.  * Revision 1.3  1992/11/19  03:00:39  ahd
  34.  * drop rcsid
  35.  *
  36.  * Revision 1.2  1992/11/15  20:11:48  ahd
  37.  * Add English display of modem status and error bits
  38.  *
  39.  */
  40.  
  41.  
  42. /*--------------------------------------------------------------------*/
  43. /*                        System include files                        */
  44. /*--------------------------------------------------------------------*/
  45.  
  46. #include <stdlib.h>
  47. #include <stdio.h>
  48. #include <string.h>
  49. #include <fcntl.h>
  50. #include <io.h>
  51. #include <time.h>
  52.  
  53. /*--------------------------------------------------------------------*/
  54. /*                         OS/2 include files                         */
  55. /*--------------------------------------------------------------------*/
  56.  
  57. #define INCL_DOSDEVIOCTL
  58. #define INCL_BASE
  59. #include <os2.h>
  60. #include <limits.h>
  61.  
  62. /*--------------------------------------------------------------------*/
  63. /*                    UUPC/extended include files                     */
  64. /*--------------------------------------------------------------------*/
  65.  
  66. #include "lib.h"
  67. #include "ulib.h"
  68. #include "ssleep.h"
  69. #include "catcher.h"
  70.  
  71. /*--------------------------------------------------------------------*/
  72. /*                          Global variables                          */
  73. /*--------------------------------------------------------------------*/
  74.  
  75. currentfile();
  76.  
  77. boolean   port_active = FALSE;  /* TRUE = port handler handler active  */
  78. static boolean   carrierdetect = FALSE;  /* Modem is not connected     */
  79.  
  80. #define LINELOG "LineData.Log"      /* log serial line data here */
  81.  
  82. static int log_handle;
  83. static int logmode = 0;             /* Not yet logging            */
  84. #define WRITING 1
  85. #define READING 2
  86. static FILE *log_stream;
  87. static boolean hangup_needed = FALSE;
  88. static boolean console = FALSE;
  89.  
  90. static current_baud = 0;
  91.  
  92. #define FAR_NULL ((PVOID) 0L)
  93.  
  94. /*--------------------------------------------------------------------*/
  95. /*           Definitions of control structures for DOS API            */
  96. /*--------------------------------------------------------------------*/
  97.  
  98. static HFILE com_handle;
  99. static struct _LINECONTROL com_attrib;
  100. static struct _RXQUEUE com_queue;
  101. static struct _MODEMSTATUS com_signals;
  102. static struct _DCBINFO com_dcbinfo;
  103.  
  104. static BYTE com_status;
  105. static USHORT com_error;
  106. static USHORT usPrevPriority;
  107.  
  108. static void ShowError( const USHORT status );
  109. static void ShowModem( const BYTE status );
  110.  
  111. /*--------------------------------------------------------------------*/
  112. /*    o p e n l i n e                                                 */
  113. /*                                                                    */
  114. /*    Open the serial port for I/O                                    */
  115. /*--------------------------------------------------------------------*/
  116.  
  117. int openline(char *name, BPS baud, const boolean direct )
  118. {
  119.    USHORT rc;
  120.    USHORT action;
  121.  
  122.    if (port_active)              /* Was the port already active?     ahd   */
  123.       closeline();               /* Yes --> Shutdown it before open  ahd   */
  124.  
  125. #ifdef UDEBUG
  126.    printmsg(15, "openline: %s, %d", name, baud);
  127. #endif
  128.  
  129. /*--------------------------------------------------------------------*/
  130. /*                      Validate the port format                      */
  131. /*--------------------------------------------------------------------*/
  132.  
  133.    if (!equal(name,"CON") && !equaln(name, "COM", 3 ))
  134.    {
  135.       printmsg(0,"openline: Communications port begin with COM, was %s",
  136.          name);
  137.       panic();
  138.    }
  139.  
  140. /*--------------------------------------------------------------------*/
  141. /*                          Perform the open                          */
  142. /*--------------------------------------------------------------------*/
  143.  
  144.    rc = DosOpen( name,
  145.                  &com_handle,
  146.                  &action,
  147.                  0L,
  148.                  0 ,
  149.                  FILE_OPEN ,
  150.                  OPEN_FLAGS_FAIL_ON_ERROR |
  151.                  OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE, 0L );
  152.  
  153. /*--------------------------------------------------------------------*/
  154. /*    Check the open worked.  We translation the common obvious       */
  155. /*    error of file in use to english, for all other errors are we    */
  156. /*    report the raw error code.                                      */
  157. /*--------------------------------------------------------------------*/
  158.  
  159.    if ( rc == ERROR_SHARING_VIOLATION)
  160.    {
  161.       printmsg(0,"Port %s already in use", name);
  162.       return TRUE;
  163.    }
  164.    else if ( rc != 0 )
  165.    {
  166.       printmsg(0,"openline: DosOpen error %d on port %s",
  167.                   (int) rc, name );
  168.       return TRUE;
  169.    }
  170.  
  171. /*--------------------------------------------------------------------*/
  172. /*                    Check for special test mode                     */
  173. /*--------------------------------------------------------------------*/
  174.  
  175.    if ( equal(name,"CON"))
  176.    {
  177.       port_active = TRUE;     /* record status for error handler        */
  178.       carrierdetect = FALSE;  /* Modem is not connected                 */
  179.       console = TRUE;
  180.       return 0;
  181.    }
  182.  
  183.    console = FALSE;
  184.  
  185. /*--------------------------------------------------------------------*/
  186. /*            Reset any errors on the communications port             */
  187. /*--------------------------------------------------------------------*/
  188.  
  189.    rc = DosDevIOCtl( &com_error, FAR_NULL, ASYNC_GETCOMMERROR ,
  190.                      IOCTL_ASYNC, com_handle);
  191.    if (rc)
  192.    {
  193.       printmsg(0,
  194.             "openline: Unable to read errors for %s, error bits %x",
  195.                name, (int) com_error );
  196.       printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  197.                (int) rc , (int) rc);
  198.    } /*if */
  199.    else if ( com_error )
  200.       ShowError( com_error );
  201.  
  202. /*--------------------------------------------------------------------*/
  203. /*                           Set baud rate                            */
  204. /*--------------------------------------------------------------------*/
  205.  
  206.    SIOSpeed(baud);
  207.  
  208. /*--------------------------------------------------------------------*/
  209. /*                        Set line attributes                         */
  210. /*--------------------------------------------------------------------*/
  211.  
  212. #ifdef UDEBUG
  213.    printmsg(15,"openline: Getting attributes");
  214. #endif
  215.  
  216.    rc = DosDevIOCtl( &com_attrib, FAR_NULL, ASYNC_GETLINECTRL, IOCTL_ASYNC,
  217.                 com_handle);
  218.                               /* Get old attributes from device      */
  219.    if (rc)
  220.    {
  221.       printmsg(0,"openline: Unable to get line attributes for %s",name);
  222.       printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  223.                (int) rc , (int) rc);
  224.       panic();
  225.    } /*if */
  226.  
  227.    com_attrib.bDataBits = 0x08; /* Use eight bit path for data      */
  228.    com_attrib.bParity   = 0x00; /* No parity                        */
  229.    com_attrib.bStopBits = 0x00; /* 1 Stop Bit                       */
  230.  
  231. #ifdef UDEBUG
  232.    printmsg(15,"openline: Setting attributes");
  233. #endif
  234.  
  235.    rc = DosDevIOCtl( FAR_NULL, &com_attrib, ASYNC_SETLINECTRL,
  236.                     IOCTL_ASYNC, com_handle);
  237.    if (rc)
  238.    {
  239.       printmsg(0,"openline: Unable to set line attributes for %s",name);
  240.       printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  241.                (int) rc , (int) rc);
  242.       panic();
  243.    } /*if */
  244.  
  245. /*--------------------------------------------------------------------*/
  246. /*                        Disable flow control                        */
  247. /*--------------------------------------------------------------------*/
  248.  
  249. #ifdef UDEBUG
  250.    printmsg(15,"openline: Getting flow control information");
  251. #endif
  252.  
  253.    rc = DosDevIOCtl( &com_dcbinfo, FAR_NULL, ASYNC_GETDCBINFO, IOCTL_ASYNC,
  254.                  com_handle);
  255.                               /* Get old attributes from device      */
  256.    if (rc)
  257.    {
  258.       printmsg(0,"openline: Unable to get line attributes for %s",name);
  259.       printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  260.                (int) rc , (int) rc);
  261.       panic();
  262.    } /*if */
  263.  
  264.    com_dcbinfo.usWriteTimeout = 2999;  /* Write timeout 30 seconds   */
  265.    com_dcbinfo.usReadTimeout = 24;     /* Read timeout .25 seconds   */
  266.    com_dcbinfo.fbCtlHndShake = (BYTE)
  267.                                (direct ? 0 : MODE_CTS_HANDSHAKE);
  268.    com_dcbinfo.fbFlowReplace = 0;
  269.                                        /* Unless rquested            */
  270.    com_dcbinfo.fbTimeout = MODE_READ_TIMEOUT | MODE_NO_WRITE_TIMEOUT;
  271.  
  272. #ifdef UDEBUG
  273.    printmsg(15,"openline: Setting dcb information");
  274. #endif
  275.  
  276.    rc = DosDevIOCtl( FAR_NULL, &com_dcbinfo, ASYNC_SETDCBINFO,
  277.                      IOCTL_ASYNC, com_handle);
  278.    if ( rc )
  279.    {
  280.       printmsg(0,"openline: Unable to set flow control for %s",name);
  281.       printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  282.                (int) rc , (int) rc);
  283.       panic();
  284.    } /*if */
  285.  
  286. /*--------------------------------------------------------------------*/
  287. /*                     Raise Data Terminal Ready                      */
  288. /*--------------------------------------------------------------------*/
  289.  
  290.    com_signals.fbModemOn = DTR_ON | RTS_ON ;
  291.    com_signals.fbModemOff = 0xff;
  292.  
  293. #ifdef UDEBUG
  294.    printmsg(15,"openline: Raising RTS/DTR");
  295. #endif
  296.  
  297.    rc = DosDevIOCtl( &com_error, &com_signals, ASYNC_SETMODEMCTRL,
  298.                      IOCTL_ASYNC, com_handle);
  299.    if (rc)
  300.    {
  301.       printmsg(0,
  302.             "openline: Unable to raise DTR/RTS for %s, error bits %#x",
  303.                   name, (int) com_error );
  304.       printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  305.                (int) rc , (int) rc);
  306.       panic();
  307.    } /*if */
  308.  
  309. /*--------------------------------------------------------------------*/
  310. /*        Log serial line data only if log file already exists        */
  311. /*--------------------------------------------------------------------*/
  312.  
  313.    log_handle = open(LINELOG, O_WRONLY | O_TRUNC | O_BINARY);
  314.    if (log_handle != -1) {
  315.  
  316. #ifdef UDEBUG
  317.       printmsg(15, "openline: logging serial line data to %s", LINELOG);
  318. #endif
  319.  
  320.       log_stream = fdopen(log_handle, "wb");
  321.    }
  322.  
  323.    port_active = TRUE;     /* record status for error handler        */
  324.    carrierdetect = FALSE;  /* Modem is not connected                 */
  325.  
  326. /*--------------------------------------------------------------------*/
  327. /*                     Up our processing priority                     */
  328. /*--------------------------------------------------------------------*/
  329.  
  330.    rc = DosGetPrty(PRTYS_PROCESS, &usPrevPriority, 0);
  331.    if (rc)
  332.    {
  333.       printmsg(0,"openline: Unable to get priority for task");
  334.       printmsg(0,"Return code from DosGetPrty was %#04x (%d)",
  335.                (int) rc , (int) rc);
  336.       panic();
  337.    } /*if */
  338.  
  339.    rc = DosSetPrty(PRTYS_PROCESS, PRTYC_TIMECRITICAL, 0, 0);
  340.    if (rc)
  341.    {
  342.       printmsg(0,"openline: Unable to set priority for task");
  343.       printmsg(0,"Return code from DosSetPrty was %#04x (%d)",
  344.                (int) rc , (int) rc);
  345.    } /*if */
  346.  
  347. /*--------------------------------------------------------------------*/
  348. /*                     Wait for port to stablize                      */
  349. /*--------------------------------------------------------------------*/
  350.  
  351.    ddelay(500);            /* Allow port to stablize          */
  352.    return 0;
  353.  
  354. } /*openline*/
  355.  
  356. /*--------------------------------------------------------------------*/
  357. /*    s r e a d                                                       */
  358. /*                                                                    */
  359. /*    Read from the serial port                                       */
  360. /*                                                                    */
  361. /*   Non-blocking read essential to "g" protocol.  See "dcpgpkt.c"    */
  362. /*   for description.                                                 */
  363. /*                                                                    */
  364. /*   This all changes in a multi-tasking system.  Requests for I/O    */
  365. /*   should get queued and an event flag given.  Then the             */
  366. /*   requesting process (e.g. gmachine()) waits for the event flag    */
  367. /*   to fire processing either a read or a write.  Could be           */
  368. /*   implemented on VAX/VMS or DG but not MS-DOS.                     */
  369. /*                                                                    */
  370. /*    OS/2 we could multitask, but we just let the system provide     */
  371. /*    a timeout for us with very little CPU usage.                    */
  372. /*--------------------------------------------------------------------*/
  373.  
  374. unsigned int sread(char *output, unsigned int wanted, unsigned int timeout)
  375. {
  376.    static char save[BUFSIZ];
  377.    static USHORT bufsize = 0;
  378.    USHORT rc;
  379.    time_t stop_time ;
  380.    time_t now ;
  381.  
  382. /*--------------------------------------------------------------------*/
  383. /*           Determine if our internal buffer has the data            */
  384. /*--------------------------------------------------------------------*/
  385.  
  386.    if (bufsize >= wanted)
  387.    {
  388.       memmove( output, save, wanted );
  389.       bufsize -= wanted;
  390.       if ( bufsize )          /* Any data left over?                 */
  391.          memmove( save, &save[wanted], bufsize );  /* Yes --> Save it*/
  392.       return wanted + bufsize;
  393.    } /* if */
  394.  
  395. /*--------------------------------------------------------------------*/
  396. /*            Reset any errors on the communications port             */
  397. /*--------------------------------------------------------------------*/
  398.  
  399.    rc = DosDevIOCtl( &com_error, FAR_NULL, ASYNC_GETCOMMERROR ,
  400.                      IOCTL_ASYNC, com_handle);
  401.  
  402.    if (rc && ! console )
  403.    {
  404.       printmsg(0,"sread: Unable to read port errors");
  405.       printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  406.                (int) rc , (int) rc);
  407.    } /*if */
  408.    else if ( com_error )
  409.       ShowError( com_error );
  410.  
  411. /*--------------------------------------------------------------------*/
  412. /*                 Determine when to stop processing                  */
  413. /*--------------------------------------------------------------------*/
  414.  
  415.    if ( timeout == 0 )
  416.    {
  417.       stop_time = 0;
  418.       now = 1;                /* Any number greater than stop time   */
  419.    }
  420.    else {
  421.       time( & now );
  422.       stop_time = now + timeout;
  423.    }
  424.  
  425. /*--------------------------------------------------------------------*/
  426. /*            Try to read any needed data into the buffer             */
  427. /*--------------------------------------------------------------------*/
  428.  
  429.    do {
  430.       USHORT needed =  (USHORT) wanted - bufsize;
  431.       USHORT port_timeout;
  432.       USHORT received = 0;
  433.  
  434. /*--------------------------------------------------------------------*/
  435. /*                     Handle an aborted program                      */
  436. /*--------------------------------------------------------------------*/
  437.  
  438.       if ( terminate_processing )
  439.       {
  440.          static boolean recurse = FALSE;
  441.          if ( ! recurse )
  442.          {
  443.             printmsg(2,"sread: User aborted processing");
  444.             recurse = TRUE;
  445.          }
  446.          return 0;
  447.       }
  448.  
  449. /*--------------------------------------------------------------------*/
  450. /*           Compute a new timeout for the read, if needed            */
  451. /*--------------------------------------------------------------------*/
  452.  
  453.       if (stop_time > now )
  454.       {
  455.          port_timeout = (USHORT) (stop_time - now) / needed * 100;
  456.          if (port_timeout < 100)
  457.             port_timeout = 100;
  458.       }
  459.       else
  460.          port_timeout = 0;
  461.  
  462.       if (( port_timeout != com_dcbinfo.usReadTimeout ) && ! console )
  463.       {
  464.          com_dcbinfo.usReadTimeout = port_timeout;
  465.          rc = DosDevIOCtl(FAR_NULL, &com_dcbinfo, ASYNC_SETDCBINFO,
  466.                           IOCTL_ASYNC, com_handle);
  467.          if ( rc )
  468.          {
  469.             printmsg(0,"sread: Unable to set timeout for comm port");
  470.             printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  471.                      (int) rc , (int) rc);
  472.             panic();
  473.          } /*if */
  474.  
  475. #ifdef UDEBUG
  476.          printmsg(15,"sread: Port time out is %ud seconds/100",
  477.                   port_timeout);
  478. #endif
  479.       } /* if */
  480.  
  481. /*--------------------------------------------------------------------*/
  482. /*                 Read the data from the serial port                 */
  483. /*--------------------------------------------------------------------*/
  484.  
  485.       rc = DosRead( com_handle, &save[bufsize], needed, &received );
  486.  
  487.       if ( rc != 0 )
  488.       {
  489.          printmsg(0,"sread: Read from comm port for %d bytes failed.",
  490.                   needed);
  491.          printmsg(0,"Return code from DosRead was %#04x (%d)",
  492.                   (int) rc , (int) rc);
  493.          bufsize = 0;
  494.          return 0;
  495.       }
  496.  
  497. #ifdef UDEBUG
  498.       printmsg(15,"sread: Want %d characters, received %d, total %d in buffer",
  499.             (int) wanted, (int) received, (int) bufsize + received);
  500. #endif
  501.  
  502.  
  503. /*--------------------------------------------------------------------*/
  504. /*                    Log the newly received data                     */
  505. /*--------------------------------------------------------------------*/
  506.  
  507.       if (log_handle != -1)
  508.       {
  509. #ifdef VERBOSE
  510.          size_t column;
  511. #endif
  512.          if (logmode != READING)
  513.          {
  514.             fputs("\nRead:  ", log_stream);
  515.             logmode = READING;
  516.          } /* if */
  517. #ifdef VERBOSE
  518.          for (column = 0; column < received; column++) {
  519.             char s[18];
  520.             itoa(0x100 | (unsigned) save[bufsize + column], s, 16);
  521.                                           /* Make it printable hex   */
  522.             fwrite(s, 1, 2, log_stream);  /* Write hex to the log    */
  523.          } /* for */
  524. #else
  525.          fwrite(&save[bufsize], 1, received, log_stream);
  526. #endif
  527.       } /* if */
  528.  
  529. /*--------------------------------------------------------------------*/
  530. /*            If we got the data, return it to the caller             */
  531. /*--------------------------------------------------------------------*/
  532.  
  533.       bufsize += received;
  534.       if ( bufsize == wanted )
  535.       {
  536.          memmove( output, save, bufsize);
  537.          bufsize = 0;
  538.  
  539.          if (debuglevel > 14)
  540.             fwrite(output,1,bufsize,stdout);
  541.  
  542.          return wanted;
  543.       } /* if */
  544.  
  545. /*--------------------------------------------------------------------*/
  546. /*                 Update the clock for the next pass                 */
  547. /*--------------------------------------------------------------------*/
  548.  
  549.       if (stop_time > 0)
  550.          time( &now );
  551.  
  552.    } while (stop_time > now);
  553.  
  554. /*--------------------------------------------------------------------*/
  555. /*         We don't have enough data; report what we do have          */
  556. /*--------------------------------------------------------------------*/
  557.  
  558.    return bufsize;
  559.  
  560. } /*sread*/
  561.  
  562.  
  563. /*--------------------------------------------------------------------*/
  564. /*    s w r i t e                                                     */
  565. /*                                                                    */
  566. /*    Write to the serial port                                        */
  567. /*--------------------------------------------------------------------*/
  568.  
  569. int swrite(char *data, unsigned int len)
  570. {
  571.    size_t bytes;
  572.    USHORT rc;
  573.  
  574.    hangup_needed = TRUE;      /* Flag that the port is now dirty  */
  575.  
  576. /*--------------------------------------------------------------------*/
  577. /*         Write the data out as the queue becomes available          */
  578. /*--------------------------------------------------------------------*/
  579.  
  580.    rc = DosWrite( com_handle, data , len, &bytes);
  581.    if (rc)
  582.    {
  583.       printmsg(0,"swrite: Write to communications port failed.");
  584.       printmsg(0,"Return code from DosWrite was %#04x (%d)",
  585.                (int) rc , (int) rc);
  586.       return bytes;
  587.    } /*if */
  588.  
  589. /*--------------------------------------------------------------------*/
  590. /*                        Log the data written                        */
  591. /*--------------------------------------------------------------------*/
  592.  
  593.    if (log_handle != -1) {
  594. #ifdef VERBOSE
  595.       char s[18];
  596. #endif
  597.       if (logmode != WRITING)
  598.       {
  599.          fputs("\nWrite: ", log_stream);
  600.          logmode = WRITING;
  601.       }
  602. #ifdef VERBOSE
  603.       for (bytes = 0; bytes < len; bytes++) {
  604.          itoa(0x100 | (unsigned) *data++, s, 16);
  605.                                         /* Make it printable hex  ahd */
  606.          fputc(s[1], log_stream);       /* Put it in the log    */
  607.          fputc(s[2], log_stream);       /* Put it in the log    */
  608.       }
  609. #else
  610.       fwrite(data, 1, len, log_stream);
  611. #endif
  612.    }
  613.  
  614. /*--------------------------------------------------------------------*/
  615. /*            Return bytes written to the port to the caller          */
  616. /*--------------------------------------------------------------------*/
  617.  
  618.    return len;
  619.  
  620. } /*swrite*/
  621.  
  622.  
  623. /*--------------------------------------------------------------------*/
  624. /*    s s e n d b r k                                                 */
  625. /*                                                                    */
  626. /*    send a break signal out the serial port                         */
  627. /*--------------------------------------------------------------------*/
  628.  
  629. void ssendbrk(unsigned int duration)
  630. {
  631.  
  632. #ifdef UDEBUG
  633.    printmsg(12, "ssendbrk: %d", duration);
  634. #endif
  635.  
  636.    DosDevIOCtl( &com_error, FAR_NULL, ASYNC_SETBREAKON, IOCTL_ASYNC,
  637.                 com_handle);
  638.  
  639.    if ( com_error )
  640.       ShowError( com_error );
  641.  
  642.    ddelay( duration == 0 ? 200 : duration);
  643.    DosDevIOCtl( &com_error, FAR_NULL, ASYNC_SETBREAKOFF, IOCTL_ASYNC,
  644.                 com_handle);
  645.  
  646.    if ( com_error )
  647.       ShowError( com_error );
  648.  
  649. } /*ssendbrk*/
  650.  
  651.  
  652. /*--------------------------------------------------------------------*/
  653. /*    c l o s e l i n e                                               */
  654. /*                                                                    */
  655. /*    Close the serial port down                                      */
  656. /*--------------------------------------------------------------------*/
  657.  
  658. void closeline(void)
  659. {
  660.    USHORT rc;
  661.  
  662.    if ( ! port_active )
  663.       panic();
  664.  
  665.    port_active = FALSE; /* flag port closed for error handler  */
  666.    hangup_needed = FALSE;  /* Don't fiddle with port any more  */
  667.  
  668. /*--------------------------------------------------------------------*/
  669. /*                           Lower priority                           */
  670. /*--------------------------------------------------------------------*/
  671.  
  672.    rc = DosSetPrty(PRTYS_PROCESS,
  673.                    usPrevPriority >> 8 ,
  674.                    usPrevPriority & 0xff, 0);
  675.    if (rc)
  676.    {
  677.       printmsg(0,"closeline: Unable to set priority for task");
  678.       printmsg(0,"Return code from DosSetPrty was %#04x (%d)",
  679.                (int) rc , (int) rc);
  680.    } /*if */
  681.  
  682. /*--------------------------------------------------------------------*/
  683. /*                             Lower DTR                              */
  684. /*--------------------------------------------------------------------*/
  685.  
  686.    com_signals.fbModemOn  = 0x00;
  687.    com_signals.fbModemOff = DTR_OFF | RTS_OFF;
  688.  
  689.  
  690.    if (DosDevIOCtl( &com_error, &com_signals, ASYNC_SETMODEMCTRL,
  691.                     IOCTL_ASYNC, com_handle))
  692.    {
  693.       printmsg(0,"closeine: Unable to lower DTR/RTS for port");
  694.    } /*if */
  695.    else if ( com_error )
  696.          ShowError( com_error );
  697.  
  698. /*--------------------------------------------------------------------*/
  699. /*                      Actually close the port                       */
  700. /*--------------------------------------------------------------------*/
  701.  
  702.    rc = DosClose( com_handle );
  703.  
  704.    if ( rc != 0 )
  705.       printmsg( 0,"Close of serial port failed, reason %d", (int) rc);
  706.  
  707. /*--------------------------------------------------------------------*/
  708. /*                   Stop logging the data to disk                    */
  709. /*--------------------------------------------------------------------*/
  710.  
  711.    if (log_handle != -1) {    /* close serial line log file */
  712.       fclose(log_stream);
  713.       close(log_handle);
  714.    };
  715.  
  716.    printmsg(3,"Serial port closed");
  717.  
  718. } /* closeline */
  719.  
  720.  
  721. /*--------------------------------------------------------------------*/
  722. /*    H a n g u p                                                     */
  723. /*                                                                    */
  724. /*    Hangup the telephone by dropping DTR.  Works with HAYES and     */
  725. /*    many compatibles.                                               */
  726. /*    14 May 89 Drew Derbyshire                                       */
  727. /*--------------------------------------------------------------------*/
  728.  
  729. void hangup( void )
  730. {
  731.    if (!hangup_needed)
  732.       return;
  733.    hangup_needed = FALSE;
  734.  
  735.    if ( console )
  736.       return;
  737.  
  738. /*--------------------------------------------------------------------*/
  739. /*                              Drop DTR                              */
  740. /*--------------------------------------------------------------------*/
  741.  
  742.    com_signals.fbModemOn  = 0x00;
  743.    com_signals.fbModemOff = DTR_OFF;
  744.  
  745.    if (DosDevIOCtl( &com_error, &com_signals, ASYNC_SETMODEMCTRL,
  746.                      IOCTL_ASYNC, com_handle))
  747.    {
  748.       printmsg(0,"hangup: Unable to lower DTR for comm port");
  749.       panic();
  750.    } /*if */
  751.    else if ( com_error )
  752.          ShowError( com_error );
  753.  
  754. /*--------------------------------------------------------------------*/
  755. /*                  Wait for the telephone to hangup                  */
  756. /*--------------------------------------------------------------------*/
  757.  
  758.    printmsg(3,"hangup: Dropped DTR");
  759.    carrierdetect = FALSE;  /* Modem is not connected                 */
  760.    ddelay(500);            /* Really only need 250 milliseconds         */
  761.  
  762. /*--------------------------------------------------------------------*/
  763. /*                          Bring DTR backup                          */
  764. /*--------------------------------------------------------------------*/
  765.  
  766.    com_signals.fbModemOn = DTR_ON;
  767.    com_signals.fbModemOff = 0xff;
  768.  
  769.    if (DosDevIOCtl( &com_error, &com_signals, ASYNC_SETMODEMCTRL,
  770.                      IOCTL_ASYNC, com_handle))
  771.    {
  772.       printmsg(0,"hangup: Unable to raise DTR for comm port");
  773.       panic();
  774.    } /*if */
  775.    else if ( com_error )
  776.          ShowError( com_error );
  777.  
  778.    ddelay(2000);           /* Now wait for the poor thing to recover    */
  779.  
  780. } /* hangup */
  781.  
  782.  
  783. /*--------------------------------------------------------------------*/
  784. /*    S I O S p e e d                                                 */
  785. /*                                                                    */
  786. /*    Re-specify the speed of an opened serial port                   */
  787. /*                                                                    */
  788. /*    Dropped the DTR off/on calls because this makes a Hayes drop    */
  789. /*    the line if configured properly, and we don't want the modem    */
  790. /*    to drop the phone on the floor if we are performing             */
  791. /*    autobaud.                                                       */
  792. /*                                                                    */
  793. /*    (Configured properly = standard method of making a Hayes        */
  794. /*    hang up the telephone, especially when you can't get it into    */
  795. /*    command state because it is at the wrong speed or whatever.)    */
  796. /*--------------------------------------------------------------------*/
  797.  
  798. void SIOSpeed(BPS baud)
  799. {
  800.    USHORT rc;
  801.  
  802. #ifdef UDEBUG
  803.    printmsg(15,"SIOSpeed: Setting baud rate to %u", (unsigned int) baud);
  804. #endif
  805.  
  806.    rc = DosDevIOCtl( FAR_NULL, &baud,
  807.                      ASYNC_SETBAUDRATE, IOCTL_ASYNC, com_handle);
  808.  
  809.    if (rc && ! console )
  810.    {
  811.       printmsg(0,"SIOSPeed: Unable to set baud rate for port to %d",
  812.                baud);
  813.       printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  814.                (int) rc , (int) rc);
  815.       panic();
  816.    } /*if */
  817.  
  818.    current_baud = baud;
  819.  
  820. } /* SIOSpeed */
  821.  
  822.  
  823. /*--------------------------------------------------------------------*/
  824. /*    f l o w c o n t r o l                                           */
  825. /*                                                                    */
  826. /*    Enable/Disable in band (XON/XOFF) flow control                  */
  827. /*--------------------------------------------------------------------*/
  828.  
  829. void flowcontrol( boolean flow )
  830. {
  831.    USHORT rc;
  832.  
  833.    if ( console )
  834.       return;
  835.  
  836.    if ( flow )
  837.        com_dcbinfo.fbFlowReplace = (char)
  838.             (com_dcbinfo.fbFlowReplace |
  839.             (MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE));
  840.    else
  841.       com_dcbinfo.fbFlowReplace = (char)
  842.             (com_dcbinfo.fbFlowReplace &
  843.             (0xff - MODE_AUTO_TRANSMIT - MODE_AUTO_RECEIVE));
  844.  
  845.    rc = DosDevIOCtl( FAR_NULL, &com_dcbinfo, ASYNC_SETDCBINFO,
  846.                      IOCTL_ASYNC, com_handle);
  847.  
  848.    if ( rc )
  849.    {
  850.       printmsg(0,"flowcontrol: Unable to set flow control");
  851.       printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  852.                (int) rc , (int) rc);
  853.       panic();
  854.    } /*if */
  855.  
  856. } /*flowcontrol*/
  857.  
  858. /*--------------------------------------------------------------------*/
  859. /*    G e t S p e e d                                                 */
  860. /*                                                                    */
  861. /*    Report current speed of communications connection               */
  862. /*--------------------------------------------------------------------*/
  863.  
  864. BPS GetSpeed( void )
  865. {
  866.    return current_baud;
  867. } /* GetSpeed */
  868.  
  869. /*--------------------------------------------------------------------*/
  870. /*   C D                                                              */
  871. /*                                                                    */
  872. /*   Return status of carrier detect                                  */
  873. /*--------------------------------------------------------------------*/
  874.  
  875. boolean CD( void )
  876. {
  877.  
  878.    boolean online = carrierdetect;
  879.    BYTE status;
  880.    static BYTE oldstatus = (BYTE) 0xDEAD;
  881.    USHORT rc;
  882.  
  883.    if ( console )
  884.       return feof( stdin ) == 0;
  885.  
  886.    rc = DosDevIOCtl( &status, 0L, ASYNC_GETMODEMINPUT, IOCTL_ASYNC,
  887.          com_handle );
  888.  
  889.    if ( rc )
  890.    {
  891.       printmsg(0,"CD: Unable to get modem status");
  892.       printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)",
  893.                (int) rc , (int) rc);
  894.       panic();
  895.    } /*if */
  896.  
  897.    if ( status != oldstatus )
  898.       ShowModem( status );
  899.  
  900.    oldstatus = status;
  901.  
  902. /*--------------------------------------------------------------------*/
  903. /*    If we previously had carrier detect but have lost it, we        */
  904. /*    report it was lost.  If we do not yet have carrier detect,      */
  905. /*    we return success because we may not have connected yet.        */
  906. /*--------------------------------------------------------------------*/
  907.  
  908.    carrierdetect = status && DCD_ON;
  909.  
  910.    if (online)
  911.       return (status && (DCD_ON && DSR_ON));
  912.    else
  913.       return (status && DSR_ON);
  914.  
  915. } /* CD */
  916.  
  917. /*--------------------------------------------------------------------*/
  918. /*    S h o w M o d e m                                               */
  919. /*                                                                    */
  920. /*    Report current modem status                                     */
  921. /*--------------------------------------------------------------------*/
  922.  
  923. #define mannounce(flag, bits, text ) ((flag & bits) ? text : "" )
  924.  
  925. static void ShowModem( const BYTE status )
  926. {
  927.    if ( debuglevel < 4 )
  928.       return;
  929.  
  930.    printmsg(0, "ShowModem: %#02x%s%s%s%s",
  931.       (int) status,
  932.       mannounce(DCD_ON,   status, "  Carrier Detect"),
  933.       mannounce(RI_ON,    status, "  Ring Indicator"),
  934.       mannounce(DSR_ON,   status, "  Data Set Ready"),
  935.       mannounce(CTS_ON,   status, "  Clear to Send"));
  936.  
  937. } /* ShowModem */
  938.  
  939. /*--------------------------------------------------------------------*/
  940. /*    S h o w E r r o r                                               */
  941. /*                                                                    */
  942. /*    Report modem error bits in English (more or less)               */
  943. /*--------------------------------------------------------------------*/
  944.  
  945. static void ShowError( const USHORT status )
  946. {
  947.    printmsg(2, "Port Error: %#04x%s%s%s%s",
  948.       (int) status,
  949.       mannounce(RX_QUE_OVERRUN,      status, "  Queue Overrrun"),
  950.       mannounce(RX_HARDWARE_OVERRUN, status, "  Hardware Overrun"),
  951.       mannounce(PARITY_ERROR,        status, "  Parity Error"),
  952.       mannounce(FRAMING_ERROR,       status, "  Framing Error"));
  953.  
  954. } /* ShowError */
  955.